home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / sharew / spiele / denker / gnuchess.gem / src / interact.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-15  |  24.1 KB  |  1,239 lines

  1. /* interact.cc - Interactive component of CHESS
  2.         (parent module of *ui.cc modules)
  3.  
  4.     This file was extracted from the original GNU Chess file nuxui.c
  5.     and converted to C++ by Warwick Allison.  It is a the generic portion
  6.     of the user interface.  1993-11-23
  7.  
  8.  
  9.     Revision: 1990-05-09
  10.  
  11.     Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc.
  12.     Copyright (c) 1988, 1989, 1990    John Stanback
  13.  
  14.     Modified extensively Nov 1989 Christopher North-Keys
  15.         40x24 two-colour display
  16.                 option for shading black squares
  17.                 expanded game save, list, and restore features using $HOME
  18.                 option to disable display of coordinates
  19.                 optional auto-updating of positional information
  20.                 optional starring of black side
  21.                 mass toggle for reverse-video functions
  22.  
  23.     This file is part of CHESS.
  24.  
  25.     CHESS is distributed in the hope that it will be useful, but WITHOUT ANY
  26.     WARRANTY.    No author or distributor accepts responsibility to anyone for
  27.     the consequences of using it or for whether it serves any particular
  28.     purpose or works at all, unless he says so in writing.    Refer to the CHESS
  29.     General Public License for full details.
  30.  
  31.     Everyone is granted permission to copy, modify and redistribute CHESS, but
  32.     only under the conditions described in the CHESS General Public License.
  33.     A copy of this license is supposed to have been given to you along with
  34.     CHESS so you can know your rights and responsibilities.    It should be in a
  35.     file named COPYING.    Among other things, the copyright notice and this
  36.     notice must be preserved on all copies.
  37. */
  38.  
  39.  
  40. #include <ctype.h>
  41. #include <signal.h>
  42. #include <stdlib.h>
  43. #include <time.h>
  44. #ifdef MSDOS
  45. #include <dos.h>
  46. #include <conio.h>
  47. #include <string.h>
  48. #else
  49. #include <sys/param.h>
  50. #include <sys/types.h>
  51. #include <sys/file.h>
  52. #include <curses.h>
  53. #undef bool // curses.h defines it to char...
  54. #undef TRUE
  55. #undef FALSE
  56. #endif /* MSDOS */
  57.  
  58. extern "C" {
  59. #include "gnuchess.h"
  60. #include "/usr/gnuchess/src/ataks.h"
  61. };
  62.  
  63. char *DRAW;
  64. int mycnt1, mycnt2;
  65.  
  66. #include "ui.h"
  67.  
  68. //#define pxx " PNBRQK"
  69. //#define qxx " pnbrqk"
  70. //#define rxx "12345678"
  71. //#define cxx "abcdefgh"
  72.  
  73. /* coordinates within a square for the following are ([1,5],[1,3]) */
  74. #define VIR_C(s)    ((flag.reverse) ? 7-column(s) : column(s))
  75. #define VIR_R(s)    ((flag.reverse) ? 7-row(s) : row(s))
  76. //#define VIR_C(s)    (column(s))
  77. //#define VIR_R(s)    (row(s))
  78. #define Vblack(s) (!((VIR_C(s) + VIR_R(s)) % 2))
  79.  
  80. static char mvstr[4][6];
  81. static long evrate;
  82. short PositionFlag = 0;
  83. short coords = 1;
  84.  
  85. void TerminateSearch (int), Die (int);
  86.  
  87. void
  88. Initialize (void)
  89. {
  90.     signal (SIGINT, Die);
  91. #ifndef MSDOS
  92.     signal (SIGQUIT, Die);
  93. #endif
  94.     ui_Initialize();
  95.     mycnt1=0;
  96.     mycnt2=0;
  97. }
  98.  
  99. void
  100. ExitChess (void)
  101. {
  102.     //ListGame ();
  103.     ui_Finalize();
  104.     exit (0);
  105. }
  106.  
  107. void
  108. Die (int Sig)
  109. {
  110.     signal (SIGINT, SIG_IGN);
  111. #ifdef MSDOS
  112.     Sig++;                                                                /* shut up the compiler */
  113. #else
  114.     signal (SIGQUIT, SIG_IGN);
  115. #endif /* MSDOS */
  116.     if (ui_AskAbort())
  117.         ExitChess ();
  118.     signal (SIGINT, Die);
  119. #ifndef MSDOS
  120.     signal (SIGQUIT, Die);
  121. #endif /* MSDOS */
  122. }
  123.  
  124. void
  125. TerminateSearch (int Sig)
  126. {
  127.     signal (SIGINT, SIG_IGN);
  128. #ifdef MSDOS
  129.     Sig++;                                                                /* shut up the compiler */
  130. #else
  131.     signal (SIGQUIT, SIG_IGN);
  132. #endif /* MSDOS */
  133.     if (!flag.timeout)
  134.         flag.musttimeout = true;
  135.     flag.bothsides = false;
  136.     signal (SIGINT, Die);
  137. #ifndef MSDOS
  138.     signal (SIGQUIT, Die);
  139. #endif /* MSDOS */
  140. }
  141.  
  142. void
  143. algbr (short int f, short int t, short int flag)
  144.  
  145. /*
  146.      Generate move strings in different formats.
  147. */
  148.  
  149. {
  150.     int m3p;
  151.  
  152.     if (f != t)
  153.         {
  154.             /* algebraic notation */
  155.             mvstr[0][0] = cxx[column (f)];
  156.             mvstr[0][1] = rxx[row (f)];
  157.             mvstr[0][2] = cxx[column (t)];
  158.             mvstr[0][3] = rxx[row (t)];
  159.             mvstr[0][4] = mvstr[3][0] = '\0';
  160.             if ((mvstr[1][0] = pxx[board[f]]) == 'P')
  161.                 {
  162.                     if (mvstr[0][0] == mvstr[0][2])                /* pawn did not eat */
  163.                         {
  164.                             mvstr[2][0] = mvstr[1][0] = mvstr[0][2];                /* to column */
  165.                             mvstr[2][1] = mvstr[1][1] = mvstr[0][3];                /* to row */
  166.                             m3p = 2;
  167.                         }
  168.                     else
  169.                         /* pawn ate */
  170.                         {
  171.                             mvstr[2][0] = mvstr[1][0] = mvstr[0][0];                /* from column */
  172.                             mvstr[2][1] = mvstr[1][1] = mvstr[0][2];                /* to column */
  173.                             mvstr[2][2] = mvstr[0][3];
  174.                             m3p = 3;                                /* to row */
  175.                         }
  176.                     mvstr[2][m3p] = mvstr[1][2] = '\0';
  177.                     if (flag & promote)
  178.                         {
  179.                             mvstr[0][4] = mvstr[1][2] = mvstr[2][m3p] = qxx[flag & pmask];
  180.                             mvstr[1][3] = mvstr[2][m3p + 1] = mvstr[0][5] = '\0';
  181.                         }
  182.                 }
  183.             else
  184.                 /* not a pawn */
  185.                 {
  186.                     mvstr[2][0] = mvstr[1][0];
  187.                     mvstr[2][1] = mvstr[0][1];
  188.                     mvstr[2][2] = mvstr[1][1] = mvstr[0][2];                /* to column */
  189.                     mvstr[2][3] = mvstr[1][2] = mvstr[0][3];                /* to row */
  190.                     mvstr[2][4] = mvstr[1][3] = '\0';
  191.                     strcpy (mvstr[3], mvstr[2]);
  192.                     mvstr[3][1] = mvstr[0][0];
  193.                     if (flag & cstlmask)
  194.                         {
  195.                             if (t > f)
  196.                                 {
  197.                                     strcpy (mvstr[1], "o-o");
  198.                                     strcpy (mvstr[2], "O-O");
  199.                                 }
  200.                             else
  201.                                 {
  202.                                     strcpy (mvstr[1], "o-o-o");
  203.                                     strcpy (mvstr[2], "O-O-O");
  204.                                 }
  205.                         }
  206.                 }
  207.         }
  208.     else
  209.         mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = '\0';
  210. }
  211.  
  212. int
  213. VerifyMove (char *s, short int iop, short unsigned int *mv)
  214.  
  215. /*
  216.      Compare the string 's' to the list of legal moves available for the
  217.      opponent. If a match is found, make the move on the board.
  218. */
  219.  
  220. {
  221.     static short pnt, tempb, tempc, tempsf, tempst, cnt;
  222.     static struct leaf xnode;
  223.     struct leaf *node;
  224.     *mv = 0;
  225.  
  226.     if (iop == 2) {
  227.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  228.         return (false);
  229.     }
  230.     cnt = 0;
  231.     MoveList (opponent, 2);
  232.     pnt = TrPnt[2];
  233.     while (pnt < TrPnt[3]) {
  234.         node = &Tree[pnt++];
  235.         algbr (node->f, node->t, (short) node->flags);
  236.         if (strcmp (s, mvstr[0]) == 0 || strcmp (s, mvstr[1]) == 0 ||
  237.                 strcmp (s, mvstr[2]) == 0 || strcmp (s, mvstr[3]) == 0) {
  238.             cnt++;
  239.             xnode = *node;
  240.         }
  241.     }
  242.     if (cnt == 1) {
  243.         MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
  244.         if (SqAtakd (PieceList[opponent][0], computer)) {
  245.             UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  246.             ShowMessage ("Illegal Move!");
  247.             return (false);
  248.         } else {
  249.             if (iop == 1)
  250.                 return (true);
  251.             UpdateDisplay (xnode.f, xnode.t, 0, (short) xnode.flags);
  252.             if ((board[xnode.t] == pawn)
  253.                     || (xnode.flags & capture)
  254.                     || (xnode.flags & cstlmask)) {
  255.                 Game50 = GameCnt;
  256.                 ZeroRPT ();
  257.             }
  258.             GameList[GameCnt].depth = GameList[GameCnt].score = 0;
  259.             GameList[GameCnt].nodes = 0;
  260.             ElapsedTime (1);
  261.             GameList[GameCnt].time = (short) (et+50)/100;
  262.             if (TCflag) {
  263.                 TimeControl.clock[opponent] -= et;
  264.                 timeopp[oppptr] = et;
  265.                 --TimeControl.moves[opponent];
  266.             }
  267.             *mv = (xnode.f << 8) | xnode.t;
  268.             algbr (xnode.f, xnode.t, false);
  269.             return (true);
  270.         }
  271.     }
  272.     if (cnt > 1) {
  273.         ShowMessage ("Ambiguous Move!");
  274.     }
  275.     return (false);
  276. }
  277.  
  278. void
  279. help (void)
  280. {
  281.     ui_GiveHelp(computer,0,flag.easy,MaxSearchDepth,dither,flag.hash);
  282. }
  283.  
  284. void
  285. EditBoard (void)
  286.  
  287. /*
  288.     Set up a board position. Pieces are entered by typing the piece
  289.     followed by the location. For example, Nf3 will place a knight on
  290.     square f3.
  291. */
  292.  
  293. {
  294.     short a, r, c, sq, i;
  295.     char s[80];
  296.  
  297.     ui_ShowEditHelp();
  298.     a = white;
  299.     do
  300.         {
  301.             ui_ShowEditColor(a);
  302.             ui_GetPieceAndLocation(s);
  303.             if (s[0] == '#')
  304.                 {
  305.                     for(sq = 0; sq < 64; sq++)
  306.                         {
  307.                             board[sq] = no_piece;
  308.                             color[sq] = neutral;
  309.                             DrawPiece (sq);
  310.                         }
  311.                 }
  312.             if (s[0] == 'c' || s[0] == 'C')
  313.                 a = otherside[a];
  314.             c = s[1] - 'a';
  315.             r = s[2] - '1';
  316.             if ((c >= 0) && (c < 8) && (r >= 0) && (r < 8))
  317.                 {
  318.                     sq = locn (r, c);
  319.                     for (i = king; i > no_piece; i--)
  320.                         if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
  321.                             break;
  322.                     board[sq] = i;
  323.                     color[sq] = (board[sq] == no_piece) ? neutral : a;        
  324.                     DrawPiece (sq);
  325.                 }
  326.     } while (s[0] != '.');
  327.  
  328.     for (sq = 0; sq < 64; sq++)
  329.         Mvboard[sq] = (board[sq] != Stboard[sq]) ? 10 : 0;
  330.     GameCnt = 0;
  331.     Game50 = 1;
  332.     ZeroRPT ();
  333.     Sdepth = 0;
  334.     InitializeStats ();
  335.     ui_ClearEditHelp();
  336.     UpdateDisplay (0, 0, 1, 0);
  337. }
  338.  
  339.  
  340.  
  341.  
  342. void
  343. ShowPlayers (void)
  344. {            
  345.     ui_ShowPlayers(flag.reverse,computer==black);
  346. }
  347.  
  348.  
  349. void
  350. ShowDepth (char ch)
  351. {
  352.     ui_ShowDepth(Sdepth,ch);
  353.     ui_RefreshEarly();
  354. }
  355.  
  356.  
  357. void
  358. ShowScore (short score)
  359. {
  360.     ui_ShowScore(score);
  361. }
  362.  
  363.  
  364. void
  365. ShowMessage (char *s)
  366. {
  367.     ui_ShowMessage(s);
  368. }
  369.  
  370.  
  371. void
  372. ClearMessage (void)
  373. {
  374.     ui_ClearMessage();
  375. }
  376.  
  377.  
  378. void
  379. ShowCurrentMove (short int pnt, short int f, short int t)
  380. {
  381.     algbr (f, t, false);
  382.     ui_ShowCurrentMove(pnt,mvstr[0]);
  383. }
  384.  
  385.  
  386. void
  387. ShowHeader (void)
  388. {
  389.     ui_ShowTitle();
  390. }
  391.  
  392.  
  393. void
  394. ShowSidetoMove (void)
  395. {
  396.     ui_ShowSideToMove(1+GameCnt/2,player);
  397. }
  398.  
  399.  
  400. void
  401. ShowPrompt (void)
  402. {
  403.     ui_PromptForMove();
  404. }
  405.  
  406.  
  407. void
  408. ShowNodeCnt (long int NodeCnt, long int evrate)
  409. {            
  410.     ui_ShowNodeCnt(NodeCnt,evrate);
  411. }
  412.  
  413.  
  414. void
  415. ShowResults (short int score, short unsigned int *bstline, char ch)
  416. {
  417.     unsigned char d, ply;
  418.     if (flag.post)
  419.         {
  420.             ShowDepth (ch);
  421.             ShowScore (score);
  422.             d = 7;
  423.             for (ply = 1; bstline[ply] > 0; ply++)
  424.                 {
  425.                     algbr ((short) bstline[ply] >> 8, (short) bstline[ply] & 0xFF, false);
  426.                     ui_ShowPlyMove(ply,mvstr[0]);
  427.                 }
  428.             ui_NoMorePly(ply);
  429.         }
  430. }
  431.  
  432.  
  433.  
  434. void
  435. SearchStartStuff (short int side)
  436. {
  437.     ui_SearchStartStuff(side);
  438. }
  439.  
  440.  
  441. void
  442. OutputMove (void)
  443. {
  444.     if(flag.illegal){ShowMessage(CP[225]);return;}
  445.  
  446.     int i;
  447.  
  448.     if (root->flags & draw)
  449.         i=1;
  450.     else if (root->score == -9999)
  451.         i=2;
  452.     else if (root->score == 9998)
  453.         i=3;
  454.     else if (root->score < -9000)
  455.         i=4;
  456.     else if (root->score > 9000)
  457.         i=5;
  458.     else
  459.         i=0;
  460.  
  461.     ui_ShowComputerMove(mvstr[0],i);
  462.  
  463.     UpdateDisplay (root->f, root->t, 0, (short) root->flags);
  464.  
  465.     if (flag.post)
  466.         {
  467.             ShowNodeCnt (NodeCnt, evrate);
  468.             for (i = 1999; i >= 0 && Tree[i].f == 0 && Tree[i].t == 0; i--);
  469.             ui_ShowMaxTree(i);
  470.         }
  471. }
  472.  
  473.  
  474.  
  475. void
  476. ElapsedTime (short int iop)
  477.  
  478. /*
  479.     Determine the time that has passed since the search was started. If
  480.     the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
  481.     timeout to true which will terminate the search.
  482. */
  483.  
  484. {
  485.     et = (time ((long *) 0) - time0) * 100;
  486.     ETnodes = NodeCnt + ZNODES;
  487.     if (et < 0)
  488.         et = 0;
  489.     if (iop == 1)
  490.         {
  491.             if (et > ResponseTime + ExtraTime && Sdepth > MINDEPTH)
  492.                 flag.timeout = true;
  493.             ETnodes = NodeCnt + ZNODES;
  494.             time0 = time ((long *) 0);
  495.         }
  496.  
  497.     UpdateClocks ();
  498. }
  499.  
  500. void
  501. UpdateClocks (void)
  502. {
  503.     short m, s;
  504.  
  505.     m = (short) (et / 6000);
  506.     s = (short) (et - 6000 * (long) m) / 100;
  507.     if (TCflag)
  508.         {
  509.             m = (short) ((TimeControl.clock[player] - et) / 6000);
  510.             s = (short) ((TimeControl.clock[player] - et - 6000 * (long) m) / 100);
  511.         }
  512.     if (m < 0)
  513.         m = 0;
  514.     if (s < 0)
  515.         s = 0;
  516.  
  517.     ui_ShowClock(flag.reverse ^ (player==white),m,s);
  518.     if (flag.post)
  519.         ShowNodeCnt (NodeCnt, evrate);
  520.     /*refresh ();*/
  521. }
  522.  
  523.  
  524. void
  525. SetTimeControl (void)
  526. {
  527.     if (TCflag)
  528.         {
  529.             TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
  530.             TimeControl.clock[white] += 6000L * TCminutes + TCseconds * 100;
  531.             TimeControl.clock[black] += 6000L * TCminutes + TCseconds * 100;
  532.         }
  533.     else
  534.         {
  535.             TimeControl.moves[white] = TimeControl.moves[black] = 0;
  536.             TimeControl.clock[white] = TimeControl.clock[black] = 0;
  537.         }
  538.     flag.onemove = (TCmoves == 1);
  539.     et = 0;
  540.     ElapsedTime (1);
  541. }
  542.  
  543. void
  544. DrawPiece (short int sq)
  545. {
  546.     ui_DrawPiece(color[sq]!=neutral,color[sq]==black,VIR_C(sq),VIR_R(sq),board[sq]);
  547. }
  548.  
  549.  
  550. void
  551. DrawSquare (short int sq)
  552. {
  553.     ui_DrawSquare(VIR_C(sq),VIR_R(sq),Vblack(sq));
  554. }
  555.  
  556.  
  557. void
  558. DrawCoords (void)
  559. {
  560.     ui_DrawCoords();
  561. }
  562.  
  563.  
  564. void
  565. ShowPostnValue (short int sq)
  566.  
  567. /*
  568.     must have called ExaminePosition() first
  569. */
  570.          
  571. {
  572.     short score;
  573.     
  574.     score = ScorePosition (color[sq]);
  575.     ui_ShowPosnValue(sq,score);
  576. }
  577.  
  578.  
  579.  
  580. void
  581. ShowPostnValues (void)
  582. {
  583.     short sq, score;
  584.  
  585.     ExaminePosition ();
  586.     for (sq = 0; sq < 64; sq++)
  587.         ShowPostnValue (sq);
  588.     score = ScorePosition (opponent);
  589.     ShowScore (score);
  590. }
  591.  
  592. void
  593. UpdateDisplay (short int f, short int t, short int redraw, short int isspec)
  594. {
  595.     short sq;
  596.     
  597.     if (redraw)
  598.         {
  599.             ShowHeader ();
  600.             ShowPlayers ();
  601.             for (sq = 0; sq < 64; sq++)
  602.                 {
  603.                     DrawSquare (sq);
  604.                     DrawPiece (sq);
  605.                 }
  606.             if (coords)
  607.                 DrawCoords ();
  608.         }
  609.     else
  610.         {
  611.             DrawPiece (f);
  612.             DrawPiece (t);
  613.             if (isspec & cstlmask)
  614.                 if (t > f)
  615.                     {
  616.                         DrawPiece (f + 3);
  617.                         DrawPiece (t - 1);
  618.                     }
  619.                 else
  620.                     {
  621.                         DrawPiece (f - 4);
  622.                         DrawPiece (t + 1);
  623.                     }
  624.             else if (isspec & epmask)
  625.                 {
  626.                     DrawPiece (t - 8);
  627.                     DrawPiece (t + 8);
  628.                 }
  629.         }
  630.     if (PositionFlag)
  631.         ShowPostnValues ();
  632.     /*refresh ();*/
  633. }
  634.  
  635. void
  636. GetGame (void)
  637. {
  638.     FILE *fd;
  639.     char fname[256];
  640.     char *tmp;
  641.     int c;
  642.     short sq;
  643.     unsigned short m;
  644.  
  645.     fname[0] = 0;
  646.     ui_GetFilename("Load",fname);
  647.  
  648.     if (fname[0]!=-1) {
  649.         if (!fname[0])
  650.             strcpy (fname, "chess.000");
  651.  
  652.         ui_ShowFileLoading(fname);
  653.  
  654.         if ((fd = fopen (fname, "r")) == NULL) {
  655.             ui_LoadFailed();
  656.             return;
  657.         }
  658.  
  659.         fscanf (fd, "%hd%hd%hd", &computer, &opponent, &Game50);
  660.         fscanf (fd, "%hd%hd", &castld[white], &castld[black]);
  661.         fscanf (fd, "%hd%hd", &TCflag, &OperatorTime);
  662.         fscanf (fd, "%ld%ld%hd%hd",
  663.                         &TimeControl.clock[white], &TimeControl.clock[black],
  664.                         &TimeControl.moves[white], &TimeControl.moves[black]);
  665.         for (sq = 0; sq < 64; sq++)
  666.             {
  667.                 fscanf (fd, "%hd%hd", &m, &Mvboard[sq]);
  668.                 board[sq] = (m >> 8);
  669.                 color[sq] = (m & 0xFF);
  670.                 if (color[sq] == 0)
  671.                     color[sq] = neutral;
  672.                 else
  673.                     --color[sq];
  674.             }
  675.         GameCnt = 0;
  676.         c = '?';
  677.         while (c != EOF)
  678.             {
  679.                 ++GameCnt;
  680.                 c = fscanf (fd, "%hd%hd%hd%ld%hd%hd%hd", &GameList[GameCnt].gmove,
  681.                                         &GameList[GameCnt].score, &GameList[GameCnt].depth,
  682.                                         &GameList[GameCnt].nodes, &GameList[GameCnt].time,
  683.                                         &GameList[GameCnt].piece, &GameList[GameCnt].color);
  684.                 if (GameList[GameCnt].color == 0)
  685.                     GameList[GameCnt].color = neutral;
  686.                 else
  687.                     --GameList[GameCnt].color;
  688.             }
  689.         GameCnt--;
  690.         if (TimeControl.clock[white] > 0)
  691.         TCflag = true;
  692.         computer--;
  693.         opponent--;
  694.  
  695.         fclose (fd);
  696.  
  697.         InitializeStats ();
  698.         Sdepth = 0;
  699.         ui_LoadDone();
  700.         UpdateDisplay (0, 0, 1, 0);
  701.     }
  702. }
  703.  
  704.  
  705. void
  706. SaveGame (void)
  707. {
  708.     FILE *fd;
  709.     char fname[256];
  710.     char *tmp;
  711.     short sq, i, c;
  712.  
  713.     fname[0] = 0;
  714.  
  715.     ui_GetFilename("Save",fname);
  716.  
  717.     if (!fname[0])
  718.         strcpy (fname, "chess.000");
  719.  
  720.     ui_ShowFileSaving(fname);
  721.  
  722.     if (NULL == (fd = fopen (fname, "w"))) {
  723.         ui_SaveFailed();
  724.         return;
  725.     }
  726.  
  727.     fprintf (fd, "%d %d %d\n", computer + 1, opponent + 1, Game50);
  728.     fprintf (fd, "%d %d\n", castld[white], castld[black]);
  729.     fprintf (fd, "%d %d\n", TCflag, OperatorTime);
  730.     fprintf (fd, "%ld %ld %d %d\n",
  731.                      TimeControl.clock[white], TimeControl.clock[black],
  732.                      TimeControl.moves[white], TimeControl.moves[black]);
  733.     for (sq = 0; sq < 64; sq++)
  734.         {
  735.             if (color[sq] == neutral)
  736.                 c = 0;
  737.             else
  738.                 c = color[sq] + 1;
  739.             fprintf (fd, "%d %d\n", 256 * board[sq] + c, Mvboard[sq]);
  740.         }
  741.     for (i = 1; i <= GameCnt; i++)
  742.         {
  743.             if (GameList[i].color == neutral)
  744.                 c = 0;
  745.             else
  746.                 c = GameList[i].color + 1;
  747.             fprintf (fd, "%d %d %d %ld %d %d %d\n",
  748.                              GameList[i].gmove, GameList[i].score, GameList[i].depth,
  749.                              GameList[i].nodes, GameList[i].time,
  750.                              GameList[i].piece, c);
  751.         }
  752.     fclose (fd);
  753.     ui_SaveDone();
  754. }
  755.  
  756.  
  757.  
  758.  
  759. void
  760. ListGame (void)
  761. {
  762.     FILE *fd;
  763.     char fname[256];
  764.     char *tmp;
  765.     short i, f, t;
  766.  
  767.     fname[0] = 0;
  768.     ui_GetFilename("List",fname);
  769.     if (!fname[0])
  770.         strcpy (fname, "chess.lst");
  771.  
  772.     if (!(fd = fopen (fname, "w"))) {
  773.         ShowMessage ("Cannot write move list");
  774.         return;
  775.     }
  776.  
  777.     fprintf (fd, "\n");
  778.     fprintf (fd, "       score  depth   nodes  time         ");
  779.     fprintf (fd, "       score  depth   nodes  time\n");
  780.     for (i = 1; i <= GameCnt; i++) {
  781.         f = GameList[i].gmove >> 8;
  782.         t = (GameList[i].gmove & 0xFF);
  783.         algbr (f, t, false);
  784.         if ((i % 2) == 1)
  785.             fprintf (fd, "\n");
  786.         else
  787.             fprintf (fd, "         ");
  788.         fprintf (fd, "%5s  %5d     %2d %7ld %5d", mvstr[0],
  789.                      GameList[i].score, GameList[i].depth,
  790.                      GameList[i].nodes, GameList[i].time);
  791.     }
  792.     fprintf (fd, "\n\n");
  793.     fclose (fd);
  794.     //ShowMessage ("Move list written");
  795. }
  796.  
  797. void
  798. Undo (void)
  799.  
  800. /*
  801.     Undo the most recent half-move.
  802. */
  803.  
  804. {
  805.     short f, t;
  806.     f = GameList[GameCnt].gmove >> 8;
  807.     t = GameList[GameCnt].gmove & 0xFF;
  808.     if (board[t] == king && distance (t, f) > 1)
  809.         (void) castle (GameList[GameCnt].color, f, t, 2);
  810.     else {
  811.         /* Check for promotion: */
  812.         if ((color[t] == white && row (f) == 6 && row (t) == 7)
  813.                 || (color[t] == black && row (f) == 1 && row (t) == 0))
  814.             {
  815.                 int g, from = f;
  816.                 for (g = GameCnt - 1; g > 0; g--)
  817.                     if (GameList[g].gmove & 0xFF == from)
  818.                         from = GameList[g].gmove >> 8;
  819.                 if ((color[t] == white && row (from) == 1)
  820.                         || (color[t] == black && row (from) == 6))
  821.                     board[t] = pawn;
  822.             }
  823.         board[f] = board[t];
  824.         color[f] = color[t];
  825.         board[t] = GameList[GameCnt].piece;
  826.         color[t] = GameList[GameCnt].color;
  827.         if (color[t] != neutral)
  828.             Mvboard[t]--;
  829.         Mvboard[f]--;
  830.     }
  831.     if (TCflag)
  832.         ++TimeControl.moves[color[f]];
  833.     GameCnt--;
  834.     computer = otherside[computer];
  835.     opponent = otherside[opponent];
  836.     flag.mate = false;
  837.     Sdepth = 0;
  838.     UpdateDisplay (0, 0, 1, 0);
  839.     InitializeStats ();
  840. }
  841.  
  842. /*
  843. void
  844. ChangeAlphaWindow (void)
  845. {
  846.     ShowMessage ("Awindow= ");
  847.     scanz ("%hd", &Awindow);
  848. }
  849.  
  850. void
  851. ChangeBetaWindow (void)
  852. {
  853.     ShowMessage ("Bwindow= ");
  854.     scanz ("%hd", &Bwindow);
  855. }
  856. */
  857.  
  858. void
  859. GiveHint (void)
  860. {
  861.     algbr ((short) (hint >> 8), (short) (hint & 0xFF), false);
  862.     ui_ShowHint(mvstr[0]);
  863. }
  864.  
  865. void
  866. ChangeSearchDepth (void)
  867. {
  868.     int msd;
  869.     ui_ChangeSearchDepth(&msd);
  870.     MaxSearchDepth=(short)msd;
  871. }
  872.  
  873.  
  874. void
  875. SetContempt (void)
  876. {
  877.     int c;
  878.     ui_ChangeContempt(&c);
  879.     contempt=(short)c;
  880. }
  881.  
  882.  
  883. /*
  884. void
  885. ChangeXwindow (void)
  886. {
  887.     ShowMessage ("xwndw= ");
  888.     scanz ("%hd", &xwndw);
  889. }
  890. */
  891.  
  892.  
  893. void SelectLevel (char *sx)
  894. {
  895.     OperatorTime = 0;
  896.     TCmoves = 60;
  897.     TCminutes = 5;
  898.     TCseconds = 0;
  899.  
  900.     int Level=1;
  901.     ui_ChangeLevel(&Level);
  902.  
  903.     switch ((int) Level)
  904.         {
  905.         case 1:
  906.             TCmoves = 60;
  907.             TCminutes = 5;
  908.             break;
  909.         case 2:
  910.             TCmoves = 60;
  911.             TCminutes = 15;
  912.             break;
  913.         case 3:
  914.             TCmoves = 60;
  915.             TCminutes = 30;
  916.             break;
  917.         case 4:
  918.             TCmoves = 40;
  919.             TCminutes = 30;
  920.             break;
  921.         case 5:
  922.             TCmoves = 40;
  923.             TCminutes = 60;
  924.             break;
  925.         case 6:
  926.             TCmoves = 40;
  927.             TCminutes = 120;
  928.             break;
  929.         case 7:
  930.             TCmoves = 40;
  931.             TCminutes = 240;
  932.             break;
  933.         case 8:
  934.             TCmoves = 1;
  935.             TCminutes = 15;
  936.             break;
  937.         case 9:
  938.             TCmoves = 1;
  939.             TCminutes = 60;
  940.             break;
  941.         case 10:
  942.             TCmoves = 1;
  943.             TCminutes = 600;
  944.             break;
  945.         }
  946.  
  947.     TCflag = (TCmoves > 0);
  948.     TimeControl.clock[white] = TimeControl.clock[black] = 0;
  949.     SetTimeControl ();
  950.     /*ClrScreen (); WHY?
  951.     UpdateDisplay (0, 0, 1, 0);*/
  952. }
  953.  
  954.  
  955. void
  956. DoDebug (void)
  957. {
  958.     short c, p, sq, tp, tc, tsq, score;
  959.     char s[40];
  960.     
  961.     ExaminePosition ();
  962.  
  963.     ui_ChoosePiece(s);
  964.  
  965.     c = neutral;
  966.     if (s[0] == 'w' || s[0] == 'W')
  967.         c = white;
  968.     if (s[0] == 'b' || s[0] == 'B')
  969.         c = black;
  970.     for(p = king; p > no_piece; p--)
  971.         if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
  972.             break;
  973.     for (sq = 0; sq < 64; sq++)
  974.         {
  975.             tp = board[sq];
  976.             tc = color[sq];
  977.             board[sq] = p;
  978.             color[sq] = c;
  979.             tsq = PieceList[c][1];
  980.             PieceList[c][1] = sq;
  981.             ShowPostnValue (sq);
  982.             PieceList[c][1] = tsq;
  983.             board[sq] = tp;
  984.             color[sq] = tc;
  985.         }
  986.     score = ScorePosition (opponent);
  987.     ShowScore (score);
  988. }
  989.  
  990. void
  991. // C header = TestSpeed(void (*f) (short int side, short int ply))
  992. TestSpeed(void f(short int side, short int ply))
  993. {
  994.     short i;
  995.     long t1, t2;
  996.  
  997.     t1 = time (0);
  998.     for (i = 0; i < 10000; i++)
  999.         {
  1000.             f (opponent, 2);
  1001.         }
  1002.     t2 = time (0);
  1003.     NodeCnt = 10000L * (TrPnt[3] - TrPnt[2]);
  1004.     evrate = NodeCnt / (t2 - t1);
  1005.     ShowNodeCnt (NodeCnt, evrate);
  1006. }
  1007.  
  1008.  
  1009. void
  1010. InputCommand (void)
  1011.  
  1012. /*
  1013.     Process the users command. If easy mode is OFF (the computer is thinking
  1014.     on opponents time) and the program is out of book, then make the 'hint'
  1015.     move on the board and call SelectMove() to find a response. The user
  1016.     terminates the search by entering ^C (quit siqnal) before entering a
  1017.     command. If the opponent does not make the hint move, then set Sdepth to
  1018.     zero.
  1019. */
  1020.  
  1021. {
  1022.     short ok, tmp;
  1023.     unsigned short mv;
  1024.     char s[80];
  1025.  
  1026.     ok = flag.quit = false;
  1027.     player = opponent;
  1028.     //ShowSidetoMove ();    // Delayed until ready to GetMove
  1029.     ft = 0;
  1030.     if (hint > 0 && !flag.easy && Book == NULL)
  1031.         {
  1032.             fflush (stdout);
  1033.             time0 = time ((long *) 0);
  1034.             algbr ((short) hint >> 8, (short) hint & 0xFF, false);
  1035.             strcpy (s, mvstr[0]);
  1036.             tmp = epsquare;
  1037.             if (VerifyMove (s, 1, &mv))
  1038.                 {
  1039.                     ShowPrompt ();
  1040.                     SelectMove (computer, 2);
  1041.                     (void) VerifyMove (mvstr[0], 2, &mv);
  1042.                     if (Sdepth > 0)
  1043.                         Sdepth--;
  1044.                 }
  1045.             ft = time ((long *) 0) - time0;
  1046.             epsquare = tmp;
  1047.         }
  1048.     signal (SIGINT, Die);
  1049. #ifndef MSDOS
  1050.     signal (SIGQUIT, Die);
  1051. #endif /* MSDOS */
  1052.     while (!(ok || flag.quit))
  1053.         {
  1054.             player = opponent;
  1055.             ShowSidetoMove();
  1056.             MoveList (opponent, 2); // For CalculateLegalMove
  1057.             ui_GetMove(s);
  1058.             ok = VerifyMove (s, 0, &mv);
  1059.             if (ok) {
  1060.                 if (mv != hint) {
  1061.                     Sdepth = 0;
  1062.                     ft = 0;
  1063.                 }
  1064.             } else if (*s == '\0')
  1065.                 UpdateDisplay (0, 0, 1, 0);
  1066.             else if (strcmp (s, "bd") == 0) {
  1067.                     /*ClrScreen ();*/
  1068.                     UpdateDisplay (0, 0, 1, 0);
  1069.             } else if ((strcmp (s, "quit") == 0) || (strcmp (s, "exit") == 0))
  1070.                 flag.quit = true;
  1071.             else if (strcmp (s, "post") == 0)
  1072.                 flag.post = !flag.post;
  1073.             else if (strcmp (s, "edit") == 0)
  1074.                 EditBoard ();
  1075.             else if (strcmp (s, "go") == 0)
  1076.                 ok = true;
  1077.             else if (strcmp (s, "help") == 0)
  1078.                 help ();
  1079.             else if (strcmp (s, "force") == 0)
  1080.                 flag.force = !flag.force;
  1081.             else if (strcmp (s, "book") == 0)
  1082.                 Book = NULL;
  1083.             else if (strcmp (s, "undo") == 0 && GameCnt > 0)
  1084.                 Undo ();
  1085.             else if (strcmp (s, "new") == 0) {
  1086.                 NewGame ();
  1087.                 UpdateDisplay (0, 0, 1, 0);
  1088.             } else if (strcmp (s, "list") == 0)
  1089.                 ListGame ();
  1090.             else if (strcmp (s, "level") == 0)
  1091.                 SelectLevel ("");
  1092.             else if (strcmp (s, "hash") == 0)
  1093.                 flag.hash = !flag.hash;
  1094.             else if (strcmp (s, "beep") == 0)
  1095.                 flag.beep = !flag.beep;
  1096. /*
  1097.             else if (strcmp (s, "Awindow") == 0)
  1098.                 ChangeAlphaWindow ();
  1099.             else if (strcmp (s, "Bwindow") == 0)
  1100.                 ChangeBetaWindow ();
  1101. */
  1102.             else if (strcmp (s, "hint") == 0)
  1103.                 GiveHint ();
  1104.             else if (strcmp (s, "both") == 0) {
  1105.                     flag.bothsides = !flag.bothsides;
  1106.                     Sdepth = 0;
  1107.                     SelectMove (opponent, 1);
  1108.                     ok = true;
  1109.             } else if (strcmp (s, "reverse") == 0) {
  1110.                     flag.reverse = !flag.reverse;
  1111.                     /*ClrScreen ();*/
  1112.                     UpdateDisplay (0, 0, 1, 0);
  1113.             }
  1114. #if !defined(MSDOS) || defined(SEVENBIT)
  1115.             else if (strcmp (s, "shade") == 0)
  1116.                 ui_ToggleShade();
  1117. #endif /* MSDOS && !SEVENBIT */
  1118.             else if (strcmp (s, "switch") == 0) {
  1119.                     computer = otherside[computer];
  1120.                     opponent = otherside[opponent];
  1121.                     flag.force = false;
  1122.                     Sdepth = 0;
  1123.                     ok = true;
  1124.             } else if (strcmp (s, "white") == 0) {
  1125.                     computer = white;
  1126.                     opponent = black;
  1127.                     ok = true;
  1128.                     flag.force = false;
  1129.                     Sdepth = 0;
  1130.             } else if (strcmp (s, "black") == 0) {
  1131.                     computer = black;
  1132.                     opponent = white;
  1133.                     ok = true;
  1134.                     flag.force = false;
  1135.                     Sdepth = 0;
  1136.             } else if (strcmp (s, "remove") == 0 && GameCnt > 1) {
  1137.                     Undo ();
  1138.                     Undo ();
  1139.             } else if (strcmp (s, "get") == 0)
  1140.                 GetGame ();
  1141.             else if (strcmp (s, "save") == 0)
  1142.                 SaveGame ();
  1143.             else if (strcmp (s, "depth") == 0)
  1144.                 ChangeSearchDepth ();
  1145.             else if (strcmp (s, "random") == 0)
  1146.                 dither = 6;
  1147.             else if (strcmp (s, "easy") == 0)
  1148.                 flag.easy = !flag.easy;
  1149.             else if (strcmp (s, "contempt") == 0)
  1150.                 SetContempt ();
  1151. /*
  1152.             else if (strcmp (s, "xwndw") == 0)
  1153.                 ChangeXwindow ();
  1154. */
  1155.             else if (strcmp (s, "coords") == 0) {
  1156.                     coords = !coords;
  1157.                     UpdateDisplay (0, 0, 1, 0);
  1158.             }
  1159. #if !defined(MSDOS) || defined(SEVENBIT)
  1160.             else if (strcmp (s, "stars") == 0)
  1161.                 ui_ToggleStars();
  1162. #endif /* MSDOS && !SEVENBIT */
  1163.             else if (strcmp (s, "test") == 0) {
  1164.                     ShowMessage("Testing MoveList Speed");
  1165.                     TestSpeed (MoveList);
  1166.                     ShowMessage("Testing CaptureList Speed");
  1167.                     TestSpeed (CaptureList);
  1168.             } else if (strcmp (s, "p") == 0)
  1169.                 ShowPostnValues ();
  1170.             else if (strcmp (s, "debug") == 0)
  1171.                 DoDebug ();
  1172.             else if (strcmp (s, "rv") == 0)
  1173.                 ui_ToggleRV();
  1174.             else
  1175.                 ui_RejectMove(s);
  1176.         }
  1177.  
  1178.     ClearMessage ();
  1179.     ElapsedTime (1);
  1180.     if (flag.force)
  1181.         {
  1182.             computer = opponent;
  1183.             opponent = otherside[computer];
  1184.         }
  1185.     signal (SIGINT, TerminateSearch);
  1186. #ifndef MSDOS
  1187.     signal (SIGQUIT, TerminateSearch);
  1188. #endif /* MSDOS */
  1189. }
  1190.  
  1191. int NeedPromotion(int x, int y)
  1192. {
  1193.     int sq=locn(y,x);
  1194.     return ((color[sq]==white && y==6) || (color[sq]==black && y==1)) && board[sq]==pawn;
  1195. }
  1196.  
  1197. int RankAt(int x,int y)
  1198. {
  1199.     return board[locn(y,x)];
  1200. }
  1201.  
  1202. int ColourAt(int x,int y)
  1203. {
  1204.     return color[locn(y,x)];
  1205. }
  1206.  
  1207.  
  1208. static int Legal[8][8];
  1209.  
  1210. void CalculateLegalMoves(int x,int y)
  1211. // Fairly fast
  1212. {
  1213.     for (int i=0; i<8; i++)
  1214.         for (int j=0; j<8; j++)
  1215.             Legal[i][j]=0;
  1216.  
  1217.     int pnt = TrPnt[2];
  1218.     while (pnt < TrPnt[3]) {
  1219.         int f=Tree[pnt].f;
  1220.         int t=Tree[pnt].t;
  1221.         if (x==column(f) && y==row(f)) {
  1222.             Legal[column(t)][row(t)]=1;
  1223.         }
  1224.         pnt++;
  1225.     }
  1226. }
  1227.  
  1228. int LegalMove(int x, int y)
  1229. // Very fast
  1230. {
  1231.     return Legal[x][y];
  1232. }
  1233.  
  1234.  
  1235. void ClrScreen()
  1236. {
  1237.     ui_ClrScreen();
  1238. }
  1239.